# -*- coding: utf-8 -*-
from KBEDebug import *

import ConstDef
from IKernel import IKernel
from logic.ModuleMgr import ModuleMgr
import time
from interfaces import *

class Kernel(IKernel):
	def __init__(self):
		IKernel.__init__(self)

		# key   函数名
		# value 函数地址
		self.funcNameToAddr = {}

		# key   消息号
		# value 回调函数信息
		self.intMsgCallback = {}

		# key   事件类型 type=string
		# value 事件字典 type={}
		self.eventCallback = {}

		self.moduleMgr = ModuleMgr()

	def init(self ,isReload):
		self.moduleMgr.init(isReload)

	def end(self):
		self.moduleMgr.end()

	def registerFunc(self, funcName, funcAddr):
		if type(funcName) != type("") or callable(funcAddr) == False:
			return False

		if self.funcNameToAddr.get(funcName) != None:
			return False

		self.funcNameToAddr[funcName] = funcAddr
		return True

	def getFuncAddr(self, funcName):
		return self.funcNameToAddr.get(funcName)

	def sendBaseMsg(self, senderEntityID, receiverEntityID, args):
		"""
		发送 baseapp 内部消息
		"""
		senderEntity = KBEngine.entities.get(senderEntityID)
		if senderEntity == None:
			# 不存在的 base 实体
			assert(False)
			return

		receiverEntity = KBEngine.entities.get(receiverEntityID)
		if receiverEntity == None:
			# 可能是别的baseapp上的，目前就一个
			assert(False)
			return

		curEnv = KBEngine.component
		if curEnv == "baseapp":
			receiverEntity.onBase2BaseMsg(senderEntityID, args)
		elif curEnv == "cellapp":
			receiverEntity.base.onCell2BaseMsg(senderEntityID, args)
		else:
			# 目前只支持 baseapp 和 cellapp
			assert(False)

	def sendCellMsg(self, senderEntityID, receiverEntityID, args):
		"""
		发送 cellapp 内部消息
		"""
		senderEntity = KBEngine.entities.get(senderEntityID)
		if senderEntity == None:
			# 不存在的 base 实体
			assert(False)
			return

		receiverEntity = KBEngine.entities.get(receiverEntityID)
		if receiverEntity == None:
			# 可能是别的baseapp上的，目前就一个
			assert(False)
			return

		curEnv = KBEngine.component
		if curEnv == "baseapp":
			receiverEntity.cell.onBase2CellMsg(senderEntityID, args)
		elif curEnv == "cellapp":
			receiverEntity.onCell2CellMsg(senderEntityID, args)
		else:
			# 出错了 
			assert(False)

	def sendClientMsg(self, receiverEntityID, args):
		"""
		发送客户端消息
		"""
		receiverEntity = KBEngine.entities.get(receiverEntityID)
		if receiverEntity == None:
			assert(False)
			return

		if receiverEntity.client == None:
			DEBUG_MSG("receiverEntityID=%d has no client." % (receiverEntityID));
			return

		blobMsg = self.packageBlobArg(args)

		curEnv = KBEngine.component
		if curEnv == "baseapp":
			receiverEntity.client.onBase2ClientMsg(blobMsg)
		elif curEnv == "cellapp":
			receiverEntity.client.onCell2ClientMsg(blobMsg)
		else:
			# 目前就支持 baseapp cellapp 的脚本层，有客户端交互逻辑 
			assert(False)

	def sendAllClientsMsgInView(self, entityID, args):
		curEnv = KBEngine.component
		if curEnv != "cellapp":
			# 目前就支持 cellapp 的脚本层
			assert(False)

		entity = KBEngine.entities.get(entityID)
		if entity == None:
			assert(False)
			return

		if entity.client == None:
			DEBUG_MSG("entityID=%d has no client." % (entityID));
			return

		blobMsg = self.packageBlobArg(args)
		entityID.allClients.onCell2ClientMsg(blobMsg)

	def sendOtherClientsMsgInView(self, entityID, args):
		curEnv = KBEngine.component
		if curEnv != "cellapp":
			# 目前就支持 cellapp 的脚本层
			assert(False)

		entity = KBEngine.entities.get(entityID)
		if entity == None:
			assert(False)
			return

		if entity.client == None:
			DEBUG_MSG("entityID=%d has no client." % (entityID));
			return

		blobMsg = self.packageBlobArg(args)
		entityID.otherClients.onCell2ClientMsg(blobMsg)

	def addIntMsgCallback(self, msgID, funcName, priority=0):
		curEnv = KBEngine.component
		if curEnv != "baseapp" and curEnv != "cellapp":
			# 目前只支持这两个
			assert(False)
			return False

		if self.funcNameToAddr.get(funcName) == None:
			DEBUG_MSG("has no funcName=%s" % (funcName))
			return False

		priorityDict = self.intMsgCallback.get(msgID)
		if priorityDict == None:
			self.intMsgCallback[msgID] = {}
			priorityDict = self.intMsgCallback.get(msgID)

		funcNameSet = priorityDict.get(priority)
		if funcNameSet == None:
			priorityDict[priority] = set()
			funcNameSet = priorityDict.get(priority)

		funcNameSet.add(funcName)

		return True

	def onIntMsg(self, senderEntityID, receiverEntityID, args):
		curEnv = KBEngine.component
		if curEnv != "baseapp" and curEnv != "cellapp":
			# 目前只支持这两个
			assert(False)
			return False

		msgID = args[0]
		priorityCallback = self.intMsgCallback.get(msgID)
		if priorityCallback == None:
			DEBUG_MSG("has no msgID=%d" %(msgID))
			return False

		priorityKeys = list(priorityCallback.keys())
		priorityKeys.sort()
		for priority in priorityKeys:
			funcNameSet = priorityCallback.get(priority)
			if funcNameSet == None:
				continue

			for funcName in funcNameSet:
				funcAddr = self.funcNameToAddr.get(funcName)
				if funcAddr == None:
					continue
				funcAddr(senderEntityID, receiverEntityID, args)

		return True

	def addEventCallback(self, eventType, eventName, funcName, priority=0):
		"""
		添加事件回调
		@eventType type=string 事件类型，通常是用entity名字来区别,可用基类名字监听所有子类的对应事件
		@eventName type=string 事件的名字
		@funcName type=string 回调函数名 通过self.registerFunc注册的
		@priority type=int 优先级
		"""
		curEnv = KBEngine.component
		if curEnv != "baseapp" and curEnv != "cellapp":
			# 目前只支持这两个
			assert(False)
			return False

		evNameList = self.eventCallback.get(eventName)
		if evNameList == None:
			self.eventCallback[eventName] = []
			evNameList = self.eventCallback.get(eventName)

		inheritRelation = {}
		# 继承关系
		if KBEngine.component == "baseapp":
			inheritRelation["ProxyEntityEvent"] = ["ProxyEntityEvent"]
			inheritRelation["InteractiveObject"] = ["InteractiveObject", "ProxyEntityEvent"]
			inheritRelation["BaseEntityEvent"] = ["BaseEntityEvent", "InteractiveObject", "ProxyEntityEvent"]
			inheritRelation["Common"] = ["Common", "BaseEntityEvent", "InteractiveObject", "ProxyEntityEvent"]
		elif KBEngine.component == "cellapp":
			inheritRelation["InteractiveObject"] = ["InteractiveObject"]
			inheritRelation["CellEntityEvent"] = ["InteractiveObject","CellEntityEvent"]
			inheritRelation["Common"] = ["Common", "InteractiveObject", "CellEntityEvent"]
		else:
			assert(False)

		newEvCb = [eventType, funcName, priority]
		for evCb in evNameList:
			if evCb[1] != newEvCb[1]:
				continue

			if evCb[0] == newEvCb[0]:
				if evCb[2] != newEvCb[2]:
					#更改一下优先级就行了
					evCb[2] = newEvCb[2]
				return

			# 当回调函数都是一样的时候，要做eventType判定
			# 新的eventType和已有的eventType是否有继承关系，有的话，就用基类的
			alreadyHasEventType = evCb[0]
			alreadyHasClassNames = inheritRelation.get(alreadyHasEventType)
			newClassNames = inheritRelation.get(eventType)
			if newClassNames == None and alreadyHasClassNames == None:
				# 不存在继承关系
				continue

			if newClassNames == None or alreadyHasClassNames == None:
				if alreadyHasClassNames == None:
					# 新的eventType是已有的eventType基类
					evCb[0] = eventType
				return

			# 剩下两个都有基类类型，优先用最顶层类的类型
			if alreadyHasEventType in newClassNames:
				evCb[0] = eventType
			return

		evNameList.append(newEvCb)
		evNameList.sort(key = lambda elem : elem[2], reverse=True)

	def onEvent(self, eventType, eventName, senderEntityID, receiverEntityID, args):
		"""
		触发事件
		@eventType type=string 事件类型，通常是用entity名字来区别,可用基类名字监听所有子类的对应事件
		@eventName type=string 事件的名字
		@senderEntityID type=int 发送者的entityID
		@receiverEntityID type=int 接收者的entityID
		@args type=list 参数列表
		"""
		curEnv = KBEngine.component
		if curEnv != "baseapp" and curEnv != "cellapp":
			# 目前只支持这两个
			assert(False)
			return False

		evNameList = self.eventCallback.get(eventName)
		if evNameList == None:
			return False

		# 继承关系
		from interfaces_common import Common
		inheritRelation = {}
		inheritRelation["Common"] = Common.Common
		inheritRelation["InteractiveObject"] = InteractiveObject.InteractiveObject
		if KBEngine.component == "baseapp":
			inheritRelation["ProxyEntityEvent"] = ProxyEntityEvent.ProxyEntityEvent
			inheritRelation["BaseEntityEvent"] = BaseEntityEvent.BaseEntityEvent
		elif KBEngine.component == "cellapp":
			inheritRelation["CellEntityEvent"] = CellEntityEvent.CellEntityEvent
		else:
			assert(False)

		receiverEntity = KBEngine.entities.get(receiverEntityID)
		for evCb in evNameList:
			evCbType = evCb[0]
			funcName = evCb[1]
			isSameType = False
			classType = inheritRelation.get(evCbType)
			if classType == None:
				if evCbType == eventType:
					isSameType = True
			else:
				if isinstance(receiverEntity, classType):
					isSameType = True

			if isSameType == False:
				continue

			funcAddr = self.funcNameToAddr.get(funcName)
			if funcAddr == None:
				continue

			funcAddr(eventType, eventName, senderEntityID, receiverEntityID, args)

		return True

	def addPropChangedCallback(self, entityID, propName, funcName, priority = 0):
		if self.getFuncAddr(funcName) == None:
			ERROR_MSG("funcName=%s not register" % (funcName))
			return False

		entity = KBEngine.entities.get(entityID)
		return entity.addPropChangedCallback(propName, funcName, priority)

	def hasPropChangedCallback(self, entityID, propName, funcName):
		entity = KBEngine.entities.get(entityID)
		return entity.hasPropChangedCallback(propName, funcName)

	def delPropChangedCallback(self, entityID, propName, funcName):
		entity = KBEngine.entities.get(entityID)
		return entity.delPropChangedCallback(propName, funcName)

	def addHeartbeat(self, entityID, funcName, interval, count):
		entity = KBEngine.entities.get(entityID)
		if entity == None:
			assert(False)
			return False
		return entity.addHeartbeat(funcName, interval, count)

	def hasHeartbeat(self, entityID, funcName):
		entity = KBEngine.entities.get(entityID)
		if entity == None:
			assert(False)
			return False
		return entity.hasHeartbeat(funcName)

	def delHeartbeat(self, entityID, funcName):
		entity = KBEngine.entities.get(entityID)
		if entity == None:
			assert(False)
			return False
		return entity.delHeartbeat(funcName)

	def parseBlobArg(self, blobMsg):
		ms = KBEngine.MemoryStream()
		ms.fill(blobMsg)

		args = []
		while ms.rpos() < ms.wpos():
			dataType = ms.pop("UINT8")
			stringType = ConstDef.VarNumType2StringType.get(dataType)
			if stringType == None:
				# 消息格式不正确，直接放弃本次解析 
				args.clear()
				return args

			var = ms.pop(stringType)
			args.append(var)

		return args

	def packageBlobArg(self, listMsg):
		ms = KBEngine.MemoryStream()

		for arg in listMsg:
			varStringType = ""
			if type(arg) == int:
				if arg >= 0:
					if arg <= ConstDef.UINT8_MAX:
						ms.append("UINT8", ConstDef.VarStringType2NumType["UINT8"])
						ms.append("UINT8", arg)
					elif arg <= ConstDef.UINT16_MAX:
						ms.append("UINT8", ConstDef.VarStringType2NumType["UINT16"])
						ms.append("UINT16", arg)
					elif arg <= ConstDef.UINT32_MAX:
						ms.append("UINT8", ConstDef.VarStringType2NumType["UINT32"])
						ms.append("UINT32", arg)
					else:
						ms.append("UINT8", ConstDef.VarStringType2NumType["UINT64"])
						ms.append("UINT64", arg)
				else:
					if arg >= ConstDef.INT8_MIN:
						ms.append("UINT8", ConstDef.VarStringType2NumType["INT8"])
						ms.append("INT8", arg)
					elif arg >= ConstDef.INT16_MIN:
						ms.append("UINT8", ConstDef.VarStringType2NumType["INT16"])
						ms.append("INT16", arg)
					elif arg >= ConstDef.INT32_MIN:
						ms.append("UINT8", ConstDef.VarStringType2NumType["INT32"])
						ms.append("INT32", arg)
					else:
						ms.append("UINT8", ConstDef.VarStringType2NumType["INT64"])
						ms.append("INT64", arg)
			elif type(arg) == float:
				if arg >= ConstDef.FLOAT_MIN and arg <= FLOAT_MAX:
					ms.append("UINT8", ConstDef.VarStringType2NumType["FLOAT"])
					ms.append("FLOAT", arg)
				else:
					ms.append("UINT8", ConstDef.VarStringType2NumType["DOUBLE"])
					ms.append("DOUBLE", arg)
			elif type(arg) == str:
					# todo unicode
					ms.append("UINT8", ConstDef.VarStringType2NumType["STRING"])
					ms.append("STRING", arg)
			else:
				# 其他类型，不能使用
				assert(False)

		return ms.bytes()

	def getDataStringType(self, arg):
		if type(arg) == int:
			if arg >= 0:
				if arg <= ConstDef.UINT8_MAX:
					return "UINT8"
				elif arg <= ConstDef.UINT16_MAX:
					return "UINT16"
				elif arg <= ConstDef.UINT32_MAX:
					return "UINT32"
				else:
					return "UINT64"
			else:
				if arg >= ConstDef.INT8_MIN:
					return "INT8"
				elif arg >= ConstDef.INT16_MIN:
					return "INT16"
				elif arg >= ConstDef.INT32_MIN:
					return "INT32"
				else:
					return "INT64"
		elif type(arg) == float:
			if arg >= ConstDef.FLOAT_MIN and arg <= FLOAT_MAX:
				return "FLOAT"
			else:
				return "DOUBLE"
		elif type(arg) == str:
			# todo unicode
			return "STRING"

		return "STRING"

	def isBaseStrType(self, strType):
		baseStrType = ["INT8","UINT8","INT16","UINT16","INT32","UINT32","INT64","UINT64","STRING","FLOAT","DOUBLE"]
		if strType in baseStrType:
			return True

		return False

	def isBaseType(self, val):
		valType = type(val)
		return (valType == int or valType == float or valType == str)

	def getSimpleNumType(self, val):
		strType = self.getDataStringType(val)
		return ConstDef.VarStringType2NumType.get(strType)